###############################################################################
# SuperLinks                                                                  #
# Copyright (c) 2000-2007 Greg Nolle (http://greg.nolle.co.uk)                #
###############################################################################
# This program is free software; you can redistribute it and/or modify it     #
# under the terms of the GNU General Public License as published by the Free  #
# Software Foundation; either version 2 of the License, or (at your option)   #
# any later version.                                                          #
#                                                                             #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       #
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for   #
# more details.                                                               ##                                                                             #
# You should have received a copy of the GNU General Public License along     #
# with this program; if not, write to the Free Software Foundation, Inc.,     #
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.                 #
###############################################################################
# ControlPanel/Databases/Links.pm.pl -> Links database conversion module      #
###############################################################################
# DON'T EDIT BELOW UNLESS YOU KNOW WHAT YOU'RE DOING!                         #
###############################################################################
package CP::Database;

BEGIN { require "System.pm.pl"; import System qw($SYSTEM); }
BEGIN { require "General.pm.pl"; import General qw($GENERAL); }
require "Standard.pm.pl";

use HTML::Dialog;
use Archive::Tar;
use URI;
use Time::Local;
use File::Path;
use File::Copy;
use Cwd;
use strict;

sub new {
  my $class = shift;
	my $self = {
	  "DB"    => undef,
    "NAME"  => "Gossamer-Threads' Links 2.0 (flat-file)",
    @_
  };
  return bless ($self, $class);
}

sub DESTROY { }

###############################################################################
# PrintFields subroutine
sub PrintFields {
  my $self = shift;
  my ($Error) = @_;

  my $Dialog = HTML::Dialog->new();

  $Error = "<p><font class=\"error\">There were errors:<ul>$Error</ul>" if ($Error);

  my $Return = $Dialog->TableRow(items => [{ body => "Database: <b>$self->{'NAME'}</b><br>Please fill out all the required (<font class=\"form-required\">*</font>) fields:".$Error, colspan => 2 }]);
  
  $Return .= $Dialog->FormTextBox(
    name      => "FORM_CATEGORIES",
    subject   => "Path to categories.db",
    required  => 1
  );

  $Return .= $Dialog->FormTextBox(
    name      => "FORM_LINKS",
    subject   => "Path to links.db",
    required  => 1
  );

  $Return .= $Dialog->FormTextBox(
    name      => "FORM_VALIDATE",
    subject   => "Path to validate.db",
    required  => 1
  );

  $Return .= $Dialog->FormTextBox(
    name      => "FORM_PASSWORD",
    subject   => "Password for Resources",
    required  => 1
  );

  $Return .= $Dialog->FormCheckBox(
    name      => "FORM_COMPRESS",
    items     => [{ value => "1", label => "Pack the new backup into a .tar or .tar.gz archive?" }]
  );
  
  $Return .= $Dialog->FormButton(
    items     => [
      { type => "submit", value => "Convert" },
      { type => "reset", value => "Cancel" }
    ], join => "&nbsp;"
  );
  
  return $Return;
}

###############################################################################
# CheckFields subroutine
sub CheckFields {
  my $self = shift;
  
  my $Error;
  
  $Error  = "<li>You didn't fill in the \"Path to categories.db\" field." if ($SL::QUERY{'FORM_CATEGORIES'} eq "");
  $Error .= "<li>You didn't fill in the \"Path to links.db\" field." if ($SL::QUERY{'FORM_LINKS'} eq "");
  $Error .= "<li>You didn't fill in the \"Path to validate.db\" field." if ($SL::QUERY{'FORM_VALIDATE'} eq "");
  $Error .= "<li>You didn't fill in the \"Password for Resources\" field." if ($SL::QUERY{'FORM_PASSWORD'} eq "");

  $Error .= "<li>The value you entered for the \"Path to categories.db\" field is invalid." unless ($SL::QUERY{'FORM_CATEGORIES'} eq "" || -e $SL::QUERY{'FORM_CATEGORIES'});
  $Error .= "<li>The value you entered for the \"Path to links.db\" field is invalid." unless ($SL::QUERY{'FORM_LINKS'} eq "" || -e $SL::QUERY{'FORM_LINKS'});
  $Error .= "<li>The value you entered for the \"Path to validate.db\" field is invalid." unless ($SL::QUERY{'FORM_VALIDATE'} eq "" || -e $SL::QUERY{'FORM_VALIDATE'});
  
  return $Error;
}

###############################################################################
# Main subroutine
sub Main {
  my $self = shift;
  my ($Log, $Exit) = @_;

  $Log->Line("", "uplevel");
  $Log->Line("Beginning conversion of $self->{'NAME'} database.\n\n", "element");

  $Log->Line("Creating new backup directory... ", "element");
  my $NewBackup = "SL-".time();
  mkdir("$SYSTEM->{'BACKUP_PATH'}/$NewBackup", 0777) || ($Log->Line("Error: $!", "error") and &$Exit);
  chmod(0777, "$SYSTEM->{'BACKUP_PATH'}/$NewBackup");
  $Log->Line("Done.", "success");
  
  $Log->Line("Converting data... ", "element");
  $Log->Line("", "uplevel");

  $Log->Line("Converting categories.db database...", "element");
  $Log->Line("", "uplevel");
  $Log->Line("Opening file... ", "element");
  open(CATEGORIES, $SL::QUERY{'FORM_CATEGORIES'}) || ($Log->Line("Error: $!", "error") and &$Exit);
  $Log->Line("Done.", "success");
  $Log->Line("Looping through data... ", "element");
	
  my (@Categories, %CategoriesIndex);
  foreach my $line (<CATEGORIES>) {
    my @line = split(/\|/, $line);
		
    my %category;
    $category{'ID'}          = $line[0];
    $category{'ORIG_TITLE'}  = $line[1];
    $category{'DESCRIPTION'} = $line[2];
    $category{'KEYWORDS'}    = $line[5];
    
    my @title = split(/\//, $category{'ORIG_TITLE'});
    
    $category{'TITLE'} = $title[$#title];
    $category{'TITLE'} =~ s/_/ /g;
    
    push(@Categories, \%category);
  }
  close(CATEGORIES);
  $Log->Line("Done.", "success");

  @Categories = sort { $a->{'ORIG_TITLE'} cmp $b->{'ORIG_TITLE'} } @Categories;

  $Log->Line("Processing data... ", "element");
  for (my $h = 0; $h <= $#Categories; $h++) {
    my $category = $Categories[$h];
       $category->{'USER_ADD'}  = "1";
       $category->{'ROOT'}      = "0";
       $category->{'RESOURCES'} = "0";

    $CategoriesIndex{ $category->{'ORIG_TITLE'} } = $h;
    
    my @title = split(/\//, $category->{'ORIG_TITLE'});
    if (scalar(@title) > 1) {
      my $root = join("/", @title[0..($#title - 1)]);
      $category->{'ROOT'} = $Categories[$CategoriesIndex{$root}]->{'ROOT'}.",".$Categories[$CategoriesIndex{$root}]->{'ID'};
    }
    
    foreach my $title (@title) {
      $title =~ s/_/ /g;
    }
    $category->{'FULL_TITLE'} = join(" / ", @title);
  }
  $Log->Line("Done.", "success");
  $Log->Line("", "downlevel");

  $Log->Line("Converting links.db database...", "element");
  $Log->Line("", "uplevel");
  $Log->Line("Opening file... ", "element");
  open(LINKS, $SL::QUERY{'FORM_LINKS'}) || ($Log->Line("Error: $!", "error") and &$Exit);
  $Log->Line("Done.", "success");
  
  $Log->Line("Looping through data... ", "element");

  my @Resources;
  my %Months = (
    "Jan"	=> 1,
    "Feb"	=> 2,
    "Mar"	=> 3,
    "Apr"	=> 4,
    "May"	=> 5,
    "Jun"	=> 6,
    "Jul"	=> 7,
    "Aug"	=> 8,
    "Sep"	=> 9,
    "Oct"	=> 10,
    "Nov"	=> 11,
    "Dec"	=> 12
  );
	
  foreach my $line (<LINKS>) {
    my %resource;
    my @line = split(/\|/, $line);

    next unless $line[1];

    $resource{'ID'}            = $line[0];
    $resource{'TITLE'}         = $line[1];
    $resource{'URL'}           = $line[2];
		
    my @date = split(/\-/, $line[3]);
    $date[1] = "Jan" unless ($Months{$date[1]});
    
    $resource{'CREATE_SECOND'} = timelocal(undef, undef, undef, $date[0], $Months{$date[1]} - 1, $date[2] - 1900, undef, undef, undef);
    $resource{'CREATE_DATE'}   = &Standard::ConvertEpochToDate($resource{'CREATE_SECOND'});
    $resource{'CREATE_TIME'}   = &Standard::ConvertEpochToTime($resource{'CREATE_SECOND'});
    $resource{'UPDATE_SECOND'} = $resource{'CREATE_SECOND'};
    $resource{'UPDATE_DATE'}   = $resource{'CREATE_DATE'};
    $resource{'UPDATE_TIME'}   = $resource{'CREATE_TIME'};

    $resource{'CATEGORY'}      = $Categories[$CategoriesIndex{$line[4]}]->{'ID'};

    $resource{'DESCRIPTION'}   = $line[5];
    $resource{'CONTACT_NAME'}  = $line[6];
    $resource{'CONTACT_EMAIL'} = $line[7];
    $resource{'HITS'}          = $line[8];
    $resource{'RATING'}        = $line[11];
    $resource{'KEYWORDS'}      = $resource{'TITLE'};
    $resource{'STATUS'}        = "1";
    $resource{'SHOW_EMAIL'}    = "1";
    $resource{'PASSWORD'}      = $SL::QUERY{'FORM_PASSWORD'};
    $resource{'REVIEWS'}       = "0";

    my $URI = URI->new($resource{'URL'});
    my @Segments = $URI->path_segments();
    my $file = pop(@Segments);
    my ($filename, $extension) = ($file =~ m/^(.*)\.(.*?)$/);

    $resource{'URL_PROTOCOL'}  = $URI->scheme();
    $resource{'URL_HOST'}      = $URI->host();
    $resource{'URL_PORT'}      = $URI->port();
    $resource{'URL_DIRECTORY'} = join("/", @Segments);
    $resource{'URL_FILENAME'}  = $filename;
    $resource{'URL_EXTENSION'} = $extension;
    $resource{'URL_QUERY'}     = $URI->query();

    $Categories[$CategoriesIndex{$line[4]}]->{'RESOURCES'}++;
    
    push(@Resources, \%resource);
  }
  close(LINKS);
  $Log->Line("Done.", "success");
  $Log->Line("", "downlevel");

  $Log->Line("Converting validate.db database...", "element");
  $Log->Line("", "uplevel");
  $Log->Line("Opening file... ", "element");
  open(VALIDATE, $SL::QUERY{'FORM_VALIDATE'}) || ($Log->Line("Error: $!", "error") and return 1);
  $Log->Line("Done.", "success");
  $Log->Line("Looping through data... ", "element");

  foreach my $line (<VALIDATE>) {
    my %resource;
    my @line = split(/\|/, $line);

    next unless $line[1];

    $resource{'ID'}            = $line[0];
    $resource{'TITLE'}         = $line[1];
    $resource{'URL'}           = $line[2];
		
    my @date = split(/\-/, $line[3]);
    $resource{'CREATE_SECOND'} = timelocal(undef, undef, undef, $date[0], $Months{$date[1]} - 1, $date[2] - 1900, undef, undef, undef);
    $resource{'CREATE_DATE'}   = &Standard::ConvertEpochToDate($resource{'CREATE_SECOND'});
    $resource{'CREATE_TIME'}   = &Standard::ConvertEpochToTime($resource{'CREATE_SECOND'});
    $resource{'UPDATE_SECOND'} = $resource{'CREATE_SECOND'};
    $resource{'UPDATE_DATE'}   = $resource{'CREATE_DATE'};
    $resource{'UPDATE_TIME'}   = $resource{'CREATE_TIME'};

    $resource{'CATEGORY'}      = $Categories[$CategoriesIndex{$line[4]}]->{'ID'};

    $resource{'DESCRIPTION'}   = $line[5];
    $resource{'CONTACT_NAME'}  = $line[6];
    $resource{'CONTACT_EMAIL'} = $line[7];
    $resource{'HITS'}          = $line[8];
    $resource{'RATING'}        = $line[11];
    $resource{'KEYWORDS'}      = $line[14];
    $resource{'STATUS'}        = "0";
    $resource{'SHOW_EMAIL'}    = "1";
    $resource{'PASSWORD'}      = $SL::QUERY{'FORM_PASSWORD'};
    $resource{'REVIEWS'}       = "0";

    my $URI = URI->new($resource{'URL'});
    my @Segments = $URI->path_segments();
    my $file = pop(@Segments);
    my ($filename, $extension) = ($file =~ m/^(.*)\.(.*?)$/);

    $resource{'URL_PROTOCOL'}  = $URI->scheme();
    $resource{'URL_HOST'}      = $URI->host();
    $resource{'URL_PORT'}      = $URI->port();
    $resource{'URL_DIRECTORY'} = join("/", @Segments);
    $resource{'URL_FILENAME'}  = $filename;
    $resource{'URL_EXTENSION'} = $extension;
    $resource{'URL_QUERY'}     = $URI->query();
    
    push(@Resources, \%resource);
  }
  close(VALIDATE);
  $Log->Line("Done.", "success");
  $Log->Line("", "downlevel");

  $Log->Line("", "downlevel");

  $Log->Line("Creating backup...", "element");
  $Log->Line("", "uplevel");

  $Log->Line("Saving Categories export file... ", "element");
  $self->mySaveTable($NewBackup, "Categories", \@Categories) || ($Log->Line("Error: $self->{'ERROR'}", "error") and &$Exit);
  $Log->Line("Done.", "success");
  $Log->Line("Saving Resources export file... ", "element");
  $self->mySaveTable($NewBackup, "Resources", \@Resources) || ($Log->Line("Error: $self->{'ERROR'}", "error") and &$Exit);
  $Log->Line("Done.", "success");
  $Log->Line("Saving Rates export file... ", "element");
  $self->mySaveTable($NewBackup, "Rates", []) || ($Log->Line("Error: $self->{'ERROR'}", "error") and &$Exit);
  $Log->Line("Done.", "success");
  $Log->Line("Saving Reviews export file... ", "element");
  $self->mySaveTable($NewBackup, "Reviews", []) || ($Log->Line("Error: $self->{'ERROR'}", "error") and &$Exit);
  $Log->Line("Done.", "success");
  
  $Log->Line("", "downlevel");

  if ($SL::QUERY{'FORM_COMPRESS'}) {
    $Log->Line("Packing the backup... ", "element");
    my $result = $self->myPack($NewBackup);
    if ($result == 1) {
      $Log->Line("Done.", "success");
      $Log->Line("Removing backup directory... ", "element");
      if (rmtree("$SYSTEM->{'BACKUP_PATH'}/$NewBackup")) {
        $Log->Line("Done.", "success");
      } else {
        $Log->Line("Error: $!", "error");
      }
    } else {
      $Log->Line("Error: $result", "error");
    }
  }
  
  $Log->Line("Writing backup description file... ", "element");
  if (open(DESC, ">$SYSTEM->{'BACKUP_PATH'}/$NewBackup.txt")) {
    print DESC "Converted database from $self->{'NAME'}.";
    close(DESC);
    $Log->Line("Done.", "success");
  } else {
    $Log->Line("Error: $!", "error");
  }

  $Log->Line("Writing backup log file... ", "element");
  if (open(LOG, ">$SYSTEM->{'BACKUP_PATH'}/$NewBackup.log")) {
    print LOG $Log->{'LOG'};
    close(LOG);
    $Log->Line("Done.", "success");
  } else {
    $Log->Line("Error: $!", "error");
  }
  
  $Log->Line("\n\n", "");
  $Log->Line("All done!", "element");
  $Log->Line("", "downlevel");

  return 1;
}

###############################################################################
# myGetTable subroutine
sub myGetTable {
  my $self = shift;
  my ($Table, $File) = @_;

  my %Columns = (
    "Categories"  => ["ID", "TITLE", "DESCRIPTION", "", "", "KEYWORDS"],
    "Links"       => ["ID", "TITLE", "URL", "DATE", "CATEGORY", "DESCRIPTION", "CONTACT_NAME", "CONTACT_EMAIL", "HITS", "", "", "RATING", "", "", "KEYWORDS"],
    "Validate"    => ["ID", "TITLE", "URL", "DATE", "CATEGORY", "DESCRIPTION", "CONTACT_NAME", "CONTACT_EMAIL", "HITS", "", "", "RATING", "", "", "KEYWORDS"]
  );
  
  open(FILE, $File) || ($self->{'ERROR'} = $! and return);
  
  my @Data;  
  foreach my $line (<FILE>) {
    my @line = split(/\|/, $line);

    my %RECORD;
    for (my $h = 0; $h <= $#{ $Columns{$Table} }; $h++) {
      next unless ($Columns{$Table}->[$h]);
      $RECORD{ $Columns{$Table}->[$h] } = $line[$h];
    }
    
    push(@Data, \%RECORD);
  }
  
  close(FILE);

  return @Data;  
}

###############################################################################
# mySaveTable subroutine
sub mySaveTable {
  my $self = shift;
  my ($Backup, $Table, $Data) = @_;

  mkdir("$SYSTEM->{'BACKUP_PATH'}/$Backup/$Table", 0777) || ($self->{'ERROR'} = $! and return);
  chmod(0777, "$SYSTEM->{'BACKUP_PATH'}/$Backup/$Table");
  
  require "$SYSTEM->{'DB_PATH'}/$Table.cfg";
  
  open(EXPORT, ">$SYSTEM->{'BACKUP_PATH'}/$Backup/$Table/$Table.export") || ($self->{'ERROR'} = $! and return);
  print EXPORT join("|", @{$DB::Columns{$Table}})."\n";
  foreach my $record (@{ $Data }) {
    print EXPORT $record->{ $DB::PrimaryKey{$Table} }."|~|".$self->{'DB'}->myEncodeData($Table, $record)."\n";
  }
  print EXPORT "#".scalar(@{ $Data });
  close(EXPORT);

  copy("$SYSTEM->{'DB_PATH'}/$Table.cfg", "$SYSTEM->{'BACKUP_PATH'}/$Backup/$Table.cfg") || ($self->{'ERROR'} = $! and return);
  
  return 1;
}

###############################################################################
# myPack subroutine
sub myPack {
  my $self = shift;
  my ($Backup) = @_;

  my $Cwd = cwd();
  chdir($SYSTEM->{'BACKUP_PATH'});

  my @Files = $self->myExplore($SYSTEM->{'BACKUP_PATH'}, $Backup);

  my $Tar = Archive::Tar->new();
     $Tar->add_files(@Files) || (chdir($Cwd) and return $Archive::Tar::error);

  if ($Archive::Tar::compression) {
    $Tar->write("$Backup.tar.gz", 1);
  } else {
    $Tar->write("$Backup.tar");
  }

  chdir($Cwd);

  return 1;
}

###############################################################################
# myExplore subroutine
sub myExplore {
  my $self = shift;
  my ($Base, $Directory) = @_;

  my @Return;

  opendir(DIR, $Base."/".$Directory);
  my @List = readdir(DIR);
  closedir(DIR);

  foreach my $file (@List) {
    next if ($file =~ /^\.\.?$/);
    
    if (-d $Base."/".$Directory."/".$file) {
      push(@Return, $self->myExplore($Base, $Directory."/".$file));
    } else {
      push(@Return, $Directory."/".$file);
    }
  }
  
  return @Return;
}

###############################################################################
# myLoadCfg subroutine
sub myLoadCfg {
  my $self = shift;
  my ($Table) = @_;

  $DB::Path{$Table} = "$SYSTEM->{'DB_PATH'}/$Table";

  if ($Table eq "Resources") {
    $DB::Table{$Table} = {
      ID                  => [ 0, "autonumber",    16, 1,           ""],
      TITLE               => [ 1,     "string",   128, 1,           ""],
      URL                 => [ 2,     "string",   256, 1,           ""],
      CATEGORY            => [ 3,     "number",    16, 1,           ""],
      DESCRIPTION         => [ 4,     "string",   512, 0,           ""],
      IMAGE               => [ 5,     "string",   512, 0,           ""],
      KEYWORDS            => [ 6,     "string",   512, 1,           ""],
      SEARCH_STRING       => [ 7,       "text",    -1, 1,           ""],
      CONTACT_NAME        => [ 8,     "string",   128, 1,           ""],
      CONTACT_EMAIL       => [ 9,     "string",   128, 1,           ""],
      SHOW_EMAIL          => [10,     "number",     1, 0,           ""],
      PASSWORD            => [11,     "string",    64, 1,           ""],
      APPROVED            => [12,     "number",     1, 0,          "0"],
      DEAD_LINK           => [13,     "number",     1, 0,          "0"],
      WEIGHTING           => [14,     "number",     3, 0,          "0"],
      HITS                => [15,     "number",     8, 0,          "0"],
      CREATE_SECOND       => [16,     "number",     9, 1,           ""],
      CREATE_DATE         => [17,     "string",    64, 1,           ""],
      CREATE_TIME         => [18,     "string",    64, 1,           ""],
      UPDATE_SECOND       => [19,     "number",     9, 0,           ""],
      UPDATE_DATE         => [20,     "string",    64, 0,           ""],
      UPDATE_TIME         => [21,     "string",    64, 0,           ""],
      MAILING_LIST        => [22,     "number",     1, 0,          "0"]
    };
    $DB::PrimaryKey{$Table} = "ID";
  } elsif ($Table eq "Categories") {
    $DB::Table{$Table} = {
      ID                  => [ 0, "autonumber",    16, 1,           ""],
      TITLE               => [ 1,     "string",    64, 1,           ""],
      DESCRIPTION         => [ 2,     "string",   256, 0,           ""],
      IMAGE               => [ 3,     "string",   512, 0,           ""],
      FULL_TITLE          => [ 4,     "string", 32768, 1,           ""],
      ROOT                => [ 5,     "string", 32768, 1,           ""],
      RESOURCES           => [ 6,     "number",    16, 0,          "0"]
    };
    $DB::PrimaryKey{$Table} = "ID";
  } elsif ($Table eq "Rates") {
    $DB::Table{$Table} = {
      ID                  => [ 0, "autonumber",    16, 1,           ""],
      LID                 => [ 1,     "number",    16, 1,           ""],
      RATE                => [ 2,     "number",     2, 1,           ""],
      IP                  => [ 3,     "string",    15, 0,           ""]
    };
    $DB::PrimaryKey{$Table} = "ID";
  } elsif ($Table eq "Reviews") {
    $DB::Table{$Table} = {
      ID                  => [ 0, "autonumber",    16, 1,           ""],
      LID                 => [ 1,     "number",    16, 1,           ""],
      REVIEW              => [ 2,       "text",    -1, 1,           ""],
      IP                  => [ 3,     "string",    15, 0,           ""],
      CREATE_SECOND       => [ 4,     "number",     9, 1,           ""],
      CREATE_DATE         => [ 5,     "string",    64, 1,           ""],
      CREATE_TIME         => [ 6,     "string",    64, 1,           ""]
    };
    $DB::PrimaryKey{$Table} = "ID";
  } elsif ($Table eq "Admins") {
    $DB::Table{$Table} = {
      USERNAME            => [ 0,     "string",    48, 1,           ""],
      PASSWORD            => [ 1,     "string",    64, 1,           ""],
      NAME                => [ 2,     "string",   128, 1,           ""],
      LEVEL_ID            => [ 3,     "number",     3, 1,           ""],
      CATEGORIES          => [ 4,     "string", 32768, 0,           ""]
    };
    $DB::PrimaryKey{$Table} = "USERNAME";
  }

  $DB::Pointer{$Table} = "";

  foreach my $Key ( sort { $DB::Table{$Table}->{$a}[0] <=> $DB::Table{$Table}->{$b}[0] } keys %{ $DB::Table{$Table} } ) {
    push ( @{ $DB::Columns{$Table} }, $Key );
    if ($Key eq $DB::PrimaryKey{$Table}) {
      $DB::Primary{$Table} = $DB::Table{$Table}->{$Key}[0];
    }
    if ($DB::Table{$Table}->{$Key}[1] eq "text") {
      $DB::TextArea{$Table}->{$Key} = $#{$DB::Columns{$Table}};
    }
  }

  return 1;
}

###############################################################################
# myClearCfg subroutine
sub myClearCfg {
  my $self = shift;
  my ($Table) = @_;

  $DB::Path{$Table} = "";
  $DB::Table{$Table} = {};
  $DB::PrimaryKey{$Table} = "";
  $DB::Pointer{$Table} = "";
  $DB::Columns{$Table} = [];
  $DB::Primary{$Table} = "";
  $DB::TextArea{$Table} = {};

  return 1;
}

1;